package com.seeTools.next.service.sys.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seeTools.next.api.entity.sys.SysUser;
import com.seeTools.next.api.entity.sys.SysUserRole;
import com.seeTools.next.common.constant.Constants;
import com.seeTools.next.common.core.PageQuery;
import com.seeTools.next.common.core.ServiceException;
import com.seeTools.next.mapper.sys.SysUserMapper;
import com.seeTools.next.service.BaseServiceImpl;
import com.seeTools.next.service.sys.ISysUserRoleService;
import com.seeTools.next.service.sys.ISysUserService;
import com.seeTools.next.util.PageQueryHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.seeTools.next.common.constant.SysConstant.DEFAULT_PASSWORD;

/**
 * <p>
 * 系统用户信息表 服务实现类
 * </p>
 *
 * @author FallenDust
 * @since 2023-04-24
 */
@CacheConfig(cacheNames = "userCache")
@Slf4j
@Service
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser> implements ISysUserService {


    @Resource
    private PageQueryHelper<SysUser> pageQueryHelper;
    @Resource
    private ISysUserRoleService sysUserRoleService;

    @Override
    public Page<SysUser> pageInfo(PageQuery<SysUser> pageQuery) {
        // 根据查询参数组装查询wrapper
        QueryWrapper<SysUser> queryWrapper = getQueryWrapper(pageQuery.getParams());
        return pageQueryHelper.pageInfo(this, pageQuery, queryWrapper);
    }

    @Override
    public void updateLastLoginTime(Long userId, String device) {
        log.debug("@updateLastLoginTime#userId={},device={}", userId, device);
        LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysUser::getId, userId)
                .set(SysUser::getLastLoginTime, LocalDateTime.now());
        this.update(updateWrapper);
    }

    @Override
    public void resetPassword(Long userId) {
        log.warn("@resetPassword#useId={},operator={}", userId, StpUtil.getLoginIdAsString());
        LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysUser::getId, userId)
                .set(SysUser::getPassword, DigestUtil.sha256Hex(DEFAULT_PASSWORD));
        // 重置密码并退出登录
        StpUtil.logout(userId);
        this.update(updateWrapper);
    }

    @Override
    @Cacheable(cacheNames = Constants.CacheKey.USER, key = "#userId", unless = "#result == null")
    public SysUser getUserCache(Long userId) {
        return this.getById(userId);
    }

    @Override
    @Cacheable(cacheNames = Constants.CacheKey.USER_ROLE_LIST, key = "#userId", unless = "#result.size() == 0")
    public List<SysUserRole> getUserRoleList(Long userId) {
        LambdaQueryWrapper<SysUserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserRole::getUserId, userId);
        return sysUserRoleService.list(queryWrapper);
    }


    @Override
    @CacheEvict(cacheNames = Constants.CacheKey.USER_ROLE_LIST, key = "#userId")
    public void assignRoles(Long userId, List<Long> roleIds) {
        // 删除当前用户的角色关联
        sysUserRoleService.removeByUserId(userId);
        // 新增用户角色关联
        List<SysUserRole> userRoleList = new ArrayList<>();
        for (Long roleId : roleIds) {
            userRoleList.add(SysUserRole.builder().userId(userId).roleId(roleId).build());
        }
        if (!userRoleList.isEmpty()) {
            sysUserRoleService.saveBatch(userRoleList);
        }
    }


    /**
     * 根据ids查询名称
     *
     * @param ids
     * @return
     */
    @Override
    public String getNameByIds(String ids) {
        List<SysUser> list = in("id", Convert.toList(ids));
        if (CollUtil.isNotEmpty(list)) {
            Set<String> collect = list.stream().map(SysUser::getUserName).collect(Collectors.toSet());
            return StrUtil.join(",", collect);
        }
        return null;
    }

    @Override
    public boolean save(SysUser entity) {
        // 用户名不能为admin
        if (Constants.ADMIN_USERNAME.equals(entity.getLoginName())) {
            throw new ServiceException("不能添加admin用户");
        }
        // 设置默认密码
        if (CharSequenceUtil.isEmpty(entity.getPassword())) {
            entity.setPassword(DEFAULT_PASSWORD);
        }
        entity.setPassword(DigestUtil.sha256Hex(entity.getPassword()));
        return super.save(entity);
    }

    @Override
    @CacheEvict(cacheNames = Constants.CacheKey.USER, key = "#entity.id")
    public boolean removeById(SysUser entity) {
        // 删除用户角色关联关系
        sysUserRoleService.removeByUserId(entity.getId());
        return super.removeById(entity);
    }


    @Override
    @CacheEvict(cacheNames = Constants.CacheKey.USER, key = "#entity.id")
    public boolean updateById(SysUser entity) {
        SysUser old = this.getById(entity.getId());
        boolean nameChanged = !old.getLoginName().equals(entity.getLoginName());
        // 用户名不能为admin
        if (nameChanged && Constants.ADMIN_USERNAME.equals(entity.getLoginName())) {
            throw new ServiceException("请更换用户名！");
        }
        return super.updateById(entity);
    }


    /**
     * 获取查询条件
     *
     * @param sysUser
     * @return
     */
    public QueryWrapper<SysUser> getQueryWrapper(SysUser sysUser) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = queryWrapper.lambda();
        if (ObjectUtil.isNotEmpty(sysUser)) {
            if (CharSequenceUtil.isNotEmpty(sysUser.getLoginName())) {
                lambdaQueryWrapper.like(SysUser::getLoginName, sysUser.getLoginName());
            }
            if (CharSequenceUtil.isNotEmpty(sysUser.getPhone())) {
                lambdaQueryWrapper.like(SysUser::getPhone, sysUser.getPhone());
            }
            if (CharSequenceUtil.isNotEmpty(sysUser.getUserName())) {
                lambdaQueryWrapper.like(SysUser::getUserName, sysUser.getUserName());
            }
        }
        return queryWrapper;
    }

}
